import Products.Apple
import Trucks.IsuzuElf
import Trucks.KamazCompass
import Trucks.MercedesBenzAtego
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.random.Random

abstract class AbstractTruck {
    abstract val weightCapacity: Double
    abstract var model: String
    abstract val products: MutableList<AbstractProduct>
    abstract val truckType: TruckType
    private val _sharedFlow: MutableSharedFlow<AbstractProduct> = MutableSharedFlow<AbstractProduct>()
    private val scope: CoroutineScope = CoroutineScope(Job() + Dispatchers.Default)
    private val truckEvents: TruckEvents = TruckEvents()
    private val mutex: Mutex = Mutex()
    val sharedFlow: SharedFlow<AbstractProduct> = _sharedFlow.asSharedFlow()

    fun load() {
        scope.launch {
            truckEvents.load(weightCapacity)
            truckEvents.sharedFlow.collect {
                println(
                    "-----------Loading Truck------------\n" +
                            "${model} ${it.productCategory.categoryName}\n" +
                            "Amount of products in storage:${Store.products.size}\n" +
                            "Current capacity: ${Store.currentCapacity}\n" +
                            "------------------------------------"
                )
                products.add(it)
            }
        }
    }

    fun unLoad() {
        var i: Int = 0
        var tempProduct: AbstractProduct
        scope.launch {
            mutex.withLock {
                while (products.size > 0) {
                    if (products[i].amount == 0) {
                        products.removeAt(i)
                        i++
                    }
                    tempProduct = products[i]
                    tempProduct.amount = 1
                    products[i].amount--
                    _sharedFlow.emit(tempProduct)
                    delay(tempProduct.shipmentDuration.toLong() * 1000)
                }
            }
            scope.cancel()
        }
    }
}

class ListOfTrucks() {
    var trucks: MutableList<AbstractTruck> = mutableListOf()

    init {
        trucks.add(IsuzuElf())
        trucks.add(KamazCompass())
        trucks.add(MercedesBenzAtego())
    }

    fun getRandom(): AbstractTruck {
        return trucks[Random.nextInt(0, trucks.size)]
    }

    fun getRandom(type: TruckType): AbstractTruck {
        val res: MutableList<AbstractTruck> = trucks.filter { it.truckType == type }.toMutableList()
        return res[Random.nextInt(0, res.size)]
    }
}